package com.meilingcloud.research.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilingcloud.biobank.domain.SampleBackup;
import com.meilingcloud.biobank.service.ISampleBackupService;
import com.meilingcloud.common.enums.QualityControlState;
import com.meilingcloud.common.enums.QualityEntryType;
import com.meilingcloud.research.domain.RwsQcEntry;
import com.meilingcloud.research.domain.RwsQcSample;
import com.meilingcloud.research.domain.RwsQualityControl;
import com.meilingcloud.research.domain.RwsQualityEntry;
import com.meilingcloud.research.domain.vo.QcEntryReportVo;
import com.meilingcloud.research.domain.vo.QcSampleBackupVo;
import com.meilingcloud.research.mapper.RwsQualityControlMapper;
import com.meilingcloud.research.service.IRwsQcEntryService;
import com.meilingcloud.research.service.IRwsQcSampleService;
import com.meilingcloud.research.service.IRwsQualityControlService;
import com.meilingcloud.research.service.IRwsQualityEntryService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 质控 Service业务层处理
 *
 * @author chenl
 * @date 2021-05-10
 */
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Service
public class RwsQualityControlServiceImpl extends ServiceImpl<RwsQualityControlMapper, RwsQualityControl> implements IRwsQualityControlService {

    private final static String qcResultSuccess = "0";
    private final static String qcResultFail = "1";
    private final IRwsQualityEntryService rwsQualityEntryService;
    private final IRwsQcEntryService rwsQcEntryService;
    private final IRwsQcSampleService rwsQcSampleService;
    private final ISampleBackupService sampleBackupService;

    @Override
    public List<RwsQualityControl> queryList(RwsQualityControl rwsQualityControl) {
        LambdaQueryWrapper<RwsQualityControl> lqw = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(rwsQualityControl.getQcName())) {
            lqw.like(RwsQualityControl::getQcName, rwsQualityControl.getQcName());
        }
        if (StringUtils.isNotBlank(rwsQualityControl.getQcState())) {
            lqw.eq(RwsQualityControl::getQcState, rwsQualityControl.getQcState());
        }
        if (CollectionUtil.isNotEmpty(rwsQualityControl.getStartDateRange())) {
            lqw.between(RwsQualityControl::getStartDate, rwsQualityControl.getStartDateRange().get(0),
                    rwsQualityControl.getStartDateRange().get(1));
        }
        return this.list(lqw);
    }

    @Override
    public List<String> queryLinkEntryIds(Long qcId) {
        List<RwsQcEntry> qcEntryList = rwsQcEntryService.list(new LambdaQueryWrapper<RwsQcEntry>().eq(RwsQcEntry::getQcId, qcId));
        List<Long> entryIds = qcEntryList.stream().map(RwsQcEntry::getQcEntryId).collect(Collectors.toList());
        List<String> collect = entryIds.stream().map(item -> String.valueOf(item)).filter(Objects::nonNull).collect(Collectors.toList());
        return collect;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean handleLinkEntry(List<RwsQcEntry> qcEntries) {
        if (CollectionUtil.isNotEmpty(qcEntries)) {
            // 先删除旧的关联数据 再添加
            rwsQcEntryService.remove(new LambdaQueryWrapper<RwsQcEntry>().eq(RwsQcEntry::getQcId, qcEntries.get(0).getQcId()));
            return rwsQcEntryService.saveBatch(qcEntries);
        }
        return false;
    }

    @Override
    public List<RwsQcSample> queryLinkSamples(Long qcId) {
        return rwsQcSampleService.list(new LambdaQueryWrapper<RwsQcSample>().eq(RwsQcSample::getQcId, qcId));
    }

    @Override
    public List<QcSampleBackupVo> handleLinkSamplesResult(List<RwsQcSample> rwsQcSamples) {
        List<Long> sampBackupIds = rwsQcSamples.stream().map(RwsQcSample::getSampBackupId).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(sampBackupIds)) {
            List<SampleBackup> sampleBackups = sampleBackupService.listByIds(sampBackupIds);
            List<SampleBackup> sampleBackupList = sampleBackupService.handleResult(sampleBackups);
            List<QcSampleBackupVo> collect = sampleBackupList.stream().map(s ->
                    rwsQcSamples.stream().filter(r -> ObjectUtil.equal(s.getSampBackupId(), r.getSampBackupId()))
                            .findFirst()
                            .map(i -> {
                                QcSampleBackupVo qcSampleBackupVo = new QcSampleBackupVo();
                                BeanUtil.copyProperties(s, qcSampleBackupVo);
                                qcSampleBackupVo.setId(i.getId());
                                qcSampleBackupVo.setQcId(i.getQcId());
                                qcSampleBackupVo.setQcEntryReals(i.getQcEntryReals());
                                return qcSampleBackupVo;
                            }).orElse(null)).collect(Collectors.toList());
            return collect;
        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean addLinkSample(List<RwsQcSample> qcSamples) {
        if (CollectionUtil.isNotEmpty(qcSamples)) {
            // 先删除旧的关联数据 再添加
            rwsQcSampleService.remove(new LambdaQueryWrapper<RwsQcSample>().eq(RwsQcSample::getQcId, qcSamples.get(0).getQcId()));
            return rwsQcSampleService.saveBatch(qcSamples);
        }
        return false;
    }

    @Override
    public boolean removeLinkSample(List<Long> qcSampIds) {
        if (CollectionUtil.isNotEmpty(qcSampIds)) {
            return rwsQcSampleService.removeByIds(qcSampIds);
        }
        return false;
    }

    @Override
    public List<RwsQualityEntry> queryLinkEntries(Long qcId) {
        List<RwsQcEntry> qcEntryList = rwsQcEntryService.list(new LambdaQueryWrapper<RwsQcEntry>().eq(RwsQcEntry::getQcId, qcId));
        if (CollectionUtil.isNotEmpty(qcEntryList)) {
            List<Long> entryIds = qcEntryList.stream().map(RwsQcEntry::getQcEntryId).collect(Collectors.toList());
            List<RwsQualityEntry> rwsQualityEntries = rwsQualityEntryService.listByIds(entryIds);
            return rwsQualityEntries;
        }
        return null;
    }

    @Override
    public boolean editQcSample(RwsQcSample qcSample) {
        return rwsQcSampleService.updateById(qcSample);
    }

    @Override
    public boolean updateQualityControl(RwsQualityControl rwsQualityControl) {
        if (StringUtils.equals(rwsQualityControl.getQcState(), QualityControlState.DONE.getCode())) {
            // 如果质控状态修改为完成，则同时生成质控结果
            List<RwsQcSample> rwsQcSamples = rwsQcSampleService.list(new LambdaQueryWrapper<RwsQcSample>()
                    .eq(RwsQcSample::getQcId, rwsQualityControl.getQcId()));
            if (CollectionUtil.isNotEmpty(rwsQcSamples)) {
                AtomicBoolean check = new AtomicBoolean(true);
                rwsQcSamples.forEach(item -> {
                    if (StringUtils.isNotBlank(item.getQcEntryReals())) {
                        List<RwsQualityEntry> qualityEntries = JSON.parseArray(item.getQcEntryReals(), RwsQualityEntry.class);
                        qualityEntries.forEach(j -> {
                            if (StringUtils.equals(j.getQcEntryType(), QualityEntryType.CALCULATION.getCode())) {
                                BigDecimal qcEntryReal = new BigDecimal((String) j.getQcEntryReal());
                                if (ObjectUtil.isNotNull(j.getQcEntryExpectMax()) && ObjectUtil.isNotNull(j.getQcEntryExpectMin())) {
                                    if (qcEntryReal.compareTo(j.getQcEntryExpectMax()) == 0
                                            || qcEntryReal.compareTo(j.getQcEntryExpectMin()) == -1) {
                                        check.set(false);
                                    }
                                } else if (ObjectUtil.isNotNull(j.getQcEntryExpectMax()) && ObjectUtil.isNull(j.getQcEntryExpectMin())) {
                                    if (qcEntryReal.compareTo(j.getQcEntryExpectMax()) == 0) {
                                        check.set(false);
                                    }
                                } else if (ObjectUtil.isNull(j.getQcEntryExpectMax()) && ObjectUtil.isNotNull(j.getQcEntryExpectMin())) {
                                    if (qcEntryReal.compareTo(j.getQcEntryExpectMin()) == -1) {
                                        check.set(false);
                                    }
                                }
                            } else if (StringUtils.equals(j.getQcEntryType(), QualityEntryType.JUDGE.getCode())) {
                                Boolean qcEntryReal = (Boolean) j.getQcEntryReal();
                                if (!qcEntryReal) {
                                    check.set(false);
                                }
                            }
                        });
                    }
                });
                if (check.get()) {
                    rwsQualityControl.setQcResult(qcResultSuccess);
                } else {
                    rwsQualityControl.setQcResult(qcResultFail);
                }
            }
        } else {
            // 如果质控状态修改为未完成，则同时删除质控结果
            rwsQualityControl.setQcResult("");
        }

        return this.updateById(rwsQualityControl);
    }

    @Override
    public List<QcEntryReportVo> queryReport(Long qcId) {
        List<RwsQcSample> rwsQcSamples = rwsQcSampleService.list(new LambdaQueryWrapper<RwsQcSample>().eq(RwsQcSample::getQcId, qcId));
        List<Long> sampBackupIds = rwsQcSamples.stream().map(RwsQcSample::getSampBackupId).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(sampBackupIds)) {
            List<SampleBackup> sampleBackups = sampleBackupService.listByIds(sampBackupIds);
            List<QcEntryReportVo> qcEntryReportVoList = new ArrayList<>();
            rwsQcSamples.stream().map(i ->
                    sampleBackups.stream().filter(j -> ObjectUtil.equal(i.getSampBackupId(), j.getSampBackupId()))
                            .findFirst()
                            .map(k -> {
                                if (StringUtils.isBlank(i.getQcEntryReals())) {
                                    return null;
                                }
                                List<RwsQualityEntry> qualityEntries = JSON.parseArray(i.getQcEntryReals(), RwsQualityEntry.class);
                                qualityEntries.forEach(item -> {
                                    QcEntryReportVo qcEntryReportVo = new QcEntryReportVo();
                                    BeanUtil.copyProperties(item, qcEntryReportVo);
                                    if (ObjectUtil.isNotEmpty(item.getQcEntryReal())) {
                                        boolean check = true;
                                        StringBuffer expect = new StringBuffer();
                                        if (StringUtils.equals(item.getQcEntryType(), QualityEntryType.CALCULATION.getCode())) {
                                            BigDecimal qcEntryReal = new BigDecimal((String) item.getQcEntryReal());
                                            if (ObjectUtil.isNotNull(item.getQcEntryExpectMax()) && ObjectUtil.isNotNull(item.getQcEntryExpectMin())) {
                                                expect.append(item.getQcEntryExpectMin());
                                                expect.append("-");
                                                expect.append(item.getQcEntryExpectMax());
                                                if (qcEntryReal.compareTo(item.getQcEntryExpectMax()) == 1
                                                        || qcEntryReal.compareTo(item.getQcEntryExpectMin()) == -1) {
                                                    check = false;
                                                }
                                            } else if (ObjectUtil.isNotNull(item.getQcEntryExpectMax()) && ObjectUtil.isNull(item.getQcEntryExpectMin())) {
                                                expect.append("<");
                                                expect.append(item.getQcEntryExpectMax());
                                                if (qcEntryReal.compareTo(item.getQcEntryExpectMax()) == 1) {
                                                    check = false;
                                                }
                                            } else if (ObjectUtil.isNull(item.getQcEntryExpectMax()) && ObjectUtil.isNotNull(item.getQcEntryExpectMin())) {
                                                expect.append(">");
                                                expect.append(item.getQcEntryExpectMin());
                                                if (qcEntryReal.compareTo(item.getQcEntryExpectMin()) == -1) {
                                                    check = false;
                                                }
                                            }
                                        } else if (StringUtils.equals(item.getQcEntryType(), QualityEntryType.JUDGE.getCode())) {
//                                            expect.append("yes");
                                            Boolean qcEntryReal = (Boolean) item.getQcEntryReal();
                                            if (!qcEntryReal) {
                                                check = false;
                                                qcEntryReportVo.setQcEntryReal("false");
                                            } else {
                                                qcEntryReportVo.setQcEntryReal("true");
                                            }
                                        }
                                        if (check) {
                                            qcEntryReportVo.setQcResult(qcResultSuccess);
                                        } else {
                                            qcEntryReportVo.setQcResult(qcResultFail);
                                        }
                                        qcEntryReportVo.setQcEntryExpect(expect.toString());
                                    }
                                    qcEntryReportVo.setSampBackupCode(k.getSampBackupCode());
                                    qcEntryReportVoList.add(qcEntryReportVo);
                                });
                                return null;
                            }).orElse(null)).collect(Collectors.toList());
            return qcEntryReportVoList;
        }
        return null;
    }
}
